package com.hntx.joymusic.musicMix;

import android.media.MediaCodec;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.os.AsyncTask;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.Log;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

public class AudioMix {

    private String mFinalMixAudioFile;

    public void mixAudios(String recordUrl, String audioUrl) {
        MixAudioTask audioTask = new MixAudioTask(recordUrl, audioUrl);
        audioTask.execute();
    }


    public class MixAudioTask extends AsyncTask<Void, Double, Boolean> {

        private String recordUrl;
        private String audioUrl;

        public MixAudioTask(String recordUrl, String audioUrl) {
            this.recordUrl = recordUrl;
            this.audioUrl = audioUrl;
        }

        @Override
        protected Boolean doInBackground(Void... params) {
            String rawAudioFile = null;
            int index = 0;
            //创建混合后的文件路径
            final String mixFilePath = "/data/1234.mp3";
            File[] rawAudioFiles = new File[2];
            rawAudioFiles[0] = new File(recordUrl);
            rawAudioFiles[1] = new File(audioUrl);
            try {
                MultiAudioMixer audioMixer = MultiAudioMixer.createAudioMixer();
                audioMixer.setOnAudioMixListener(new MultiAudioMixer.OnAudioMixListener() {
                    FileOutputStream fosRawMixAudio = new FileOutputStream(mixFilePath);

                    @Override
                    public void onMixing(byte[] mixBytes) throws IOException {
                        fosRawMixAudio.write(mixBytes);
                    }

                    @Override
                    public void onMixError(int errorCode) {
                        try {
                            if (fosRawMixAudio != null)
                                fosRawMixAudio.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onMixComplete() {
                        try {
                            if (fosRawMixAudio != null)
                                fosRawMixAudio.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                });
                audioMixer.mixAudios(rawAudioFiles);
                rawAudioFile = mixFilePath;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            AudioEncoder accEncoder = AudioEncoder.createAccEncoder(rawAudioFile);
            //最终地址
            String finalMixPath = "MainApplication.RECORD_AUDIO_PATH" + "/MixAudioTest.acc";
            accEncoder.encodeToFile(finalMixPath);
            //最完整的混音后存放地址
            mFinalMixAudioFile = finalMixPath;
            return true;
        }

        @Override
        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);
//            Toast.makeText(this, "混音成功，并编码成ACC格式", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 合成视频1的音频和视频2的图像
     *
     * @param audioVideoPath       提供音频的视频
     * @param audioStartTime       音频的开始时间
     * @param frameVideoPath       提供图像的视频
     * @param combinedVideoOutFile 合成后的文件
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public static void combineTwoVideos(String audioVideoPath,
                                        long audioStartTime,
                                        String frameVideoPath,
                                        File combinedVideoOutFile) {
        MediaExtractor mediaExtractor = new MediaExtractor();
        int mainAudioExtractorTrackIndex = -1; //提供音频的视频的音频轨（有点拗口）
        int mainAudioMuxerTrackIndex = -1; //合成后的视频的音频轨
        int mainAudioMaxInputSize = 0; //能获取的音频的最大值

        MediaExtractor frameVideoExtractor = new MediaExtractor();
        int frameExtractorTrackIndex = -1; //视频轨
        int frameMuxerTrackIndex = -1; //合成后的视频的视频轨
        int frameMaxInputSize = 0; //能获取的视频的最大值
        int frameRate = 0; //视频的帧率
        long frameDuration = 0;

        MediaMuxer muxer = null; //用于合成音频与视频

        try {
            muxer = new MediaMuxer(combinedVideoOutFile.getPath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);

            mediaExtractor.setDataSource(audioVideoPath); //设置视频源
            //音轨信息
            int audioTrackCount = mediaExtractor.getTrackCount(); //获取数据源的轨道数
            //在此循环轨道数，目的是找到我们想要的音频轨
            for (int i = 0; i < audioTrackCount; i++) {
                MediaFormat format = mediaExtractor.getTrackFormat(i); //得到指定索引的记录格式
                String mimeType = format.getString(MediaFormat.KEY_MIME); //主要描述mime类型的媒体格式
                if (mimeType.startsWith("audio/")) { //找到音轨
                    mainAudioExtractorTrackIndex = i;
                    mainAudioMuxerTrackIndex = muxer.addTrack(format); //将音轨添加到MediaMuxer，并返回新的轨道
                    mainAudioMaxInputSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE); //得到能获取的有关音频的最大值
//                    mainAudioDuration = format.getLong(MediaFormat.KEY_DURATION);
                }
            }

            //图像信息
            frameVideoExtractor.setDataSource(frameVideoPath); //设置视频源
            int trackCount = frameVideoExtractor.getTrackCount(); //获取数据源的轨道数
            //在此循环轨道数，目的是找到我们想要的视频轨
            for (int i = 0; i < trackCount; i++) {
                MediaFormat format = frameVideoExtractor.getTrackFormat(i); //得到指定索引的媒体格式
                String mimeType = format.getString(MediaFormat.KEY_MIME); //主要描述mime类型的媒体格式
                if (mimeType.startsWith("video/")) { //找到视频轨
                    frameExtractorTrackIndex = i;
                    frameMuxerTrackIndex = muxer.addTrack(format); //将视频轨添加到MediaMuxer，并返回新的轨道
                    frameMaxInputSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE); //得到能获取的有关视频的最大值
                    frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE); //获取视频的帧率
                    frameDuration = format.getLong(MediaFormat.KEY_DURATION); //获取视频时长
                }
            }

            muxer.start(); //开始合成

            mediaExtractor.selectTrack(mainAudioExtractorTrackIndex); //将提供音频的视频选择到音轨上
            MediaCodec.BufferInfo audioBufferInfo = new MediaCodec.BufferInfo();
            ByteBuffer audioByteBuffer = ByteBuffer.allocate(mainAudioMaxInputSize);
            while (true) {
                int readSampleSize = mediaExtractor.readSampleData(audioByteBuffer, 0); //检索当前编码的样本并将其存储在字节缓冲区中
                if (readSampleSize < 0) { //如果没有可获取的样本则退出循环
                    mediaExtractor.unselectTrack(mainAudioExtractorTrackIndex);
                    break;
                }

                long sampleTime = mediaExtractor.getSampleTime(); //获取当前展示样本的时间（单位毫秒）

                if (sampleTime < audioStartTime) { //如果样本时间小于我们想要的开始时间就快进
                    mediaExtractor.advance(); //推进到下一个样本，类似快进
                    continue;
                }

                if (sampleTime > audioStartTime + frameDuration) { //如果样本时间大于开始时间+视频时长，就退出循环
                    break;
                }
                //设置样本编码信息
                audioBufferInfo.size = readSampleSize;
                audioBufferInfo.offset = 0;
                audioBufferInfo.flags = mediaExtractor.getSampleFlags();
                audioBufferInfo.presentationTimeUs = sampleTime - audioStartTime;

                muxer.writeSampleData(mainAudioMuxerTrackIndex, audioByteBuffer, audioBufferInfo); //将样本写入
                mediaExtractor.advance(); //推进到下一个样本，类似快进
            }

            frameVideoExtractor.selectTrack(frameExtractorTrackIndex); //将提供视频图像的视频选择到视频轨上
            MediaCodec.BufferInfo videoBufferInfo = new MediaCodec.BufferInfo();
            ByteBuffer videoByteBuffer = ByteBuffer.allocate(frameMaxInputSize);
            while (true) {
                int readSampleSize = frameVideoExtractor.readSampleData(videoByteBuffer, 0); //检索当前编码的样本并将其存储在字节缓冲区中
                if (readSampleSize < 0) { //如果没有可获取的样本则退出循环
                    frameVideoExtractor.unselectTrack(frameExtractorTrackIndex);
                    break;
                }
                //设置样本编码信息
                videoBufferInfo.size = readSampleSize;
                videoBufferInfo.offset = 0;
                videoBufferInfo.flags = frameVideoExtractor.getSampleFlags();
                videoBufferInfo.presentationTimeUs += 1000 * 1000 / frameRate;

                muxer.writeSampleData(frameMuxerTrackIndex, videoByteBuffer, videoBufferInfo); //将样本写入
                frameVideoExtractor.advance(); //推进到下一个样本，类似快进
            }
        } catch (IOException e) {
            Log.e("TAG", "combineTwoVideos: ", e);
        } finally {
            //释放资源
            mediaExtractor.release();
            frameVideoExtractor.release();
            if (muxer != null) {
                muxer.release();
            }
        }
    }

    public void readVideoBg(String mVideoPath, String audioPath) {
        try {
            FileOutputStream outputStream = null;
            MediaExtractor mVideoExtractor = new MediaExtractor();
            outputStream = new FileOutputStream(new File(audioPath));
            mVideoExtractor.setDataSource(mVideoPath);
            MediaFormat format;
            for (int i = 0; i < mVideoExtractor.getTrackCount(); i++) {
                format = mVideoExtractor.getTrackFormat(i);
                if (format.getString(MediaFormat.KEY_MIME).startsWith("audio/")) {
                    mVideoExtractor.selectTrack(i);
                    break;
                }
            }
            ByteBuffer buffer = ByteBuffer.allocate(100 * 1024);
            while (true) {
                int sampleSize = mVideoExtractor.readSampleData(buffer, 0);
                if (sampleSize < 0) {
                    break;
                }
                outputStream.write(buffer.array());
                // do something
                mVideoExtractor.advance(); // 移动到下一帧
            }
            outputStream.close();
            mVideoExtractor.release();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
